#!/usr/bin/env python3
"""
深入搜索Lingma二进制中的字符映射表
"""

import subprocess
import struct

def search_mapping_patterns():
    """搜索可能的映射表模式"""
    print("🔍 === 搜索字符映射表 ===\n")
    
    # 我们知道的映射
    known_mappings = {
        0xa1: ord('m'),  # 161 -> 109
        0xf3: ord('o'),  # 243 -> 111
        0x6b: ord('d'),  # 107 -> 100
        0x31: ord('e'),  # 49 -> 101
        0xb0: ord('l'),  # 176 -> 108
        0x69: ord('"'),  # 105 -> 34
        0x01: ord(':'),  # 1 -> 58
        0x90: ord(' ')   # 144 -> 32
    }
    
    print("已知的映射:")
    for src, dst in sorted(known_mappings.items()):
        print(f"  0x{src:02x}({src}) -> 0x{dst:02x}({dst}) '{chr(dst)}'")
    
    # 在二进制中搜索256字节的映射表
    print("\n搜索256字节映射表...")
    
    with open('Lingma', 'rb') as f:
        data = f.read()
    
    # 搜索包含已知映射的256字节段
    found_tables = []
    
    for offset in range(len(data) - 256):
        # 检查这个256字节段是否包含我们已知的映射
        potential_table = data[offset:offset+256]
        
        # 验证已知映射
        matches = 0
        for src, dst in known_mappings.items():
            if potential_table[src] == dst:
                matches += 1
        
        # 如果大部分映射匹配，这可能是映射表
        if matches >= 6:  # 至少6个匹配
            found_tables.append((offset, matches, potential_table))
    
    print(f"\n找到 {len(found_tables)} 个可能的映射表")
    
    # 分析找到的表
    for i, (offset, matches, table) in enumerate(found_tables[:5]):
        print(f"\n候选表 {i+1}:")
        print(f"  偏移: 0x{offset:08x}")
        print(f"  匹配数: {matches}/8")
        
        # 显示部分内容
        print("  前16字节:", table[:16].hex())
        
        # 验证是否是有效的映射表
        # 好的映射表应该包含可打印字符
        printable_count = sum(1 for b in table if 32 <= b <= 126)
        print(f"  可打印字符: {printable_count}/256")
        
        # 保存候选表
        with open(f'candidate_table_{i+1}.bin', 'wb') as f:
            f.write(table)

def search_reverse_mapping():
    """搜索反向映射（从明文到密文）"""
    print("\n\n🔄 === 搜索反向映射表 ===")
    
    # 反向映射：明文字符位置存储对应的密文值
    reverse_known = {
        ord('m'): 0xa1,
        ord('o'): 0xf3,
        ord('d'): 0x6b,
        ord('e'): 0x31,
        ord('l'): 0xb0,
        ord('"'): 0x69,
        ord(':'): 0x01,
        ord(' '): 0x90
    }
    
    with open('Lingma', 'rb') as f:
        data = f.read()
    
    found_reverse = []
    
    for offset in range(len(data) - 256):
        potential_table = data[offset:offset+256]
        
        matches = 0
        for src, dst in reverse_known.items():
            if src < 256 and potential_table[src] == dst:
                matches += 1
        
        if matches >= 6:
            found_reverse.append((offset, matches, potential_table))
    
    print(f"找到 {len(found_reverse)} 个可能的反向映射表")
    
    for i, (offset, matches, table) in enumerate(found_reverse[:5]):
        print(f"\n反向候选表 {i+1}:")
        print(f"  偏移: 0x{offset:08x}")
        print(f"  匹配数: {matches}/8")
        
        # 保存
        with open(f'reverse_table_{i+1}.bin', 'wb') as f:
            f.write(table)

def search_in_data_section():
    """在数据段中搜索"""
    print("\n\n📊 === 在数据段中搜索 ===")
    
    # 获取段信息
    result = subprocess.run(['readelf', '-S', 'Lingma'], 
                          capture_output=True, text=True)
    
    # 解析.data和.rodata段
    data_sections = []
    for line in result.stdout.split('\n'):
        if '.data' in line or '.rodata' in line:
            parts = line.split()
            if len(parts) >= 6:
                name = parts[1]
                offset = int(parts[4], 16)
                size = int(parts[5], 16)
                data_sections.append((name, offset, size))
                print(f"找到段: {name} at 0x{offset:08x}, size: {size}")
    
    # 在数据段中搜索
    with open('Lingma', 'rb') as f:
        for name, offset, size in data_sections:
            print(f"\n搜索 {name} 段...")
            f.seek(offset)
            section_data = f.read(size)
            
            # 搜索包含我们的字符集的区域
            our_charset = b"!#%&()*,.@ABCDEFGHIJKLMNOPQRSTUVWXYZ^_abcdefghijklmnopqrstuvwxyz"
            
            # 搜索字符集
            pos = 0
            while True:
                pos = section_data.find(our_charset[:10], pos)
                if pos == -1:
                    break
                
                print(f"  在偏移 0x{offset + pos:08x} 找到字符集片段")
                
                # 查看周围的数据
                start = max(0, pos - 256)
                end = min(len(section_data), pos + 256)
                surrounding = section_data[start:end]
                
                with open(f'charset_surrounding_{name}_{pos}.bin', 'wb') as f:
                    f.write(surrounding)
                
                pos += 1

def analyze_string_references():
    """分析字符串引用"""
    print("\n\n🔗 === 分析字符串引用 ===")
    
    # 使用strings查找包含加密相关的字符串
    result = subprocess.run(['strings', '-t', 'x', 'Lingma'], 
                          capture_output=True, text=True)
    
    encryption_keywords = [
        'encrypt', 'decrypt', 'encode', 'decode', 
        'cipher', 'transform', 'substitute', 'map',
        'base64', 'table', 'alphabet', 'charset'
    ]
    
    relevant_strings = []
    for line in result.stdout.split('\n'):
        if ' ' in line:
            offset_str, string = line.split(' ', 1)
            lower_string = string.lower()
            
            for keyword in encryption_keywords:
                if keyword in lower_string:
                    offset = int(offset_str, 16)
                    relevant_strings.append((offset, string))
                    break
    
    print(f"找到 {len(relevant_strings)} 个相关字符串")
    for offset, string in relevant_strings[:20]:
        print(f"  0x{offset:08x}: {string[:80]}")

def try_decode_with_table(table_file, data_file='decoded_result.bin'):
    """使用找到的表尝试解密"""
    print(f"\n\n🔐 === 使用 {table_file} 尝试解密 ===")
    
    try:
        with open(table_file, 'rb') as f:
            table = f.read()
        
        with open(data_file, 'rb') as f:
            encrypted = f.read()
        
        # 创建映射
        mapping = {}
        for i in range(256):
            mapping[i] = table[i]
        
        # 解密
        decrypted = bytearray()
        for byte in encrypted[:500]:  # 只测试前500字节
            decrypted.append(mapping.get(byte, byte))
        
        # 检查结果
        printable = sum(1 for b in decrypted if 32 <= b <= 126)
        print(f"可打印字符: {printable}/500 ({printable/500*100:.1f}%)")
        
        # 检查JSON特征
        if b'"' in decrypted and b':' in decrypted:
            print("✓ 包含JSON特征")
            
            # 显示部分结果
            preview = bytearray()
            for b in decrypted[:200]:
                if 32 <= b <= 126:
                    preview.append(b)
                else:
                    preview.append(ord('?'))
            
            print(f"预览: {bytes(preview).decode('ascii')}")
            
            # 保存完整解密
            with open(f'decrypted_with_{table_file}.txt', 'wb') as f:
                full_decrypted = bytearray()
                for byte in encrypted:
                    full_decrypted.append(mapping.get(byte, byte))
                f.write(full_decrypted)
            
            return True
    except:
        pass
    
    return False

def search_xor_patterns():
    """搜索XOR模式的映射"""
    print("\n\n⊕ === 搜索XOR映射模式 ===")
    
    # 检查是否是简单的XOR
    known_mappings = {
        0xa1: ord('m'),
        0xf3: ord('o'),
        0x6b: ord('d'),
        0x31: ord('e'),
        0xb0: ord('l'),
        0x69: ord('"'),
        0x01: ord(':'),
        0x90: ord(' ')
    }
    
    # 计算XOR值
    xor_values = []
    for src, dst in known_mappings.items():
        xor_val = src ^ dst
        xor_values.append(xor_val)
        print(f"0x{src:02x} ^ 0x{dst:02x} = 0x{xor_val:02x}")
    
    # 检查是否有固定的XOR值
    if len(set(xor_values)) == 1:
        print(f"\n发现固定XOR值: 0x{xor_values[0]:02x}")
    else:
        print(f"\n不是简单的XOR，XOR值各不相同: {[hex(x) for x in set(xor_values)]}")

if __name__ == "__main__":
    # 搜索映射表
    search_mapping_patterns()
    search_reverse_mapping()
    search_in_data_section()
    analyze_string_references()
    search_xor_patterns()
    
    # 尝试使用找到的表解密
    print("\n\n🧪 === 测试候选映射表 ===")
    
    import os
    for i in range(1, 6):
        if os.path.exists(f'candidate_table_{i}.bin'):
            success = try_decode_with_table(f'candidate_table_{i}.bin')
            if success:
                print(f"\n✅ candidate_table_{i}.bin 可能是正确的映射表!")
        
        if os.path.exists(f'reverse_table_{i}.bin'):
            success = try_decode_with_table(f'reverse_table_{i}.bin')
            if success:
                print(f"\n✅ reverse_table_{i}.bin 可能是正确的映射表!")
    
    print("\n\n💡 === 建议 ===")
    print("1. 检查生成的候选表文件")
    print("2. 查看charset_surrounding_*.bin文件寻找线索")
    print("3. 如果找到正确的表，查看decrypted_with_*.txt")
    print("4. 映射表可能是动态生成的，需要分析生成算法")